/**
 * Provides a generic model for the AC, MQ, instruction, and index registers and the location
 * counter.  The register is modeled as an integer and provides methods to
 * get and set the value of the registers.<br><br>
 * Change Log:<br>
 * 	- 05/22/09 - Meghan Day<br>
 * 		- Created skeleton<br><br>
 *  - 05/25/09 - Ben Tarney<br>
 *  	- Filled in skeleton/ operations<br><br>
 *  - 05/25/09 - Ben Tarney<br>
 *  	- Added the ability to check overflow for specified register size<br><br>
 *  - 05/26/09 - Meghan Day<br>
 *  	- Moved getOpCode method from Memory to Register.<br>
 *  	- Changed rep of reg to int.<br>
 *  	- Added methods to get XR, debug, IOWD, addr flag, and address field bits.<br><br>
 *  - 05/27/09 - Ben Tarney<br>
 *  	- filled in error output<br><br>
 *  - 05/28/09 - Meghan Day<br>
 *  	- Fixed problems with some of the get methods due to leading 0's being lost.
 */
public class Register {
	
	
	/** Representation of the register.
	 */
	private int reg;
	/** Int value of the length of register/ number of bits.
	*/
	private int numOfBits;
	/** Holds int value of max value.
	 */
	private int maxValue;
	/** Holds int value of min value.
	 */
	private int minValue;
	
	/**
	 * One-argument constructor to create a register of the given length.
	 * @param length Length of register to create.
	 */
	public Register(int length){
		reg = 0;
		numOfBits = length;
		if (length == 32) {
			maxValue = Integer.MAX_VALUE;
			minValue = Integer.MIN_VALUE;
		}
		else if (length == 16) {
			maxValue = Short.MAX_VALUE;
			minValue = Short.MIN_VALUE;
		}
		else {
			maxValue = (int) Math.pow(2,numOfBits)-1;
			minValue = (int) (-Math.pow(2,numOfBits));
		}
	}
	
	/**
	 * Sets the value of the register to the provided integer value.
	 * @param value The value to set the register to.
	 */
	public void setValue(int value){
		if( value <= maxValue && value >= minValue){
		reg = value;
		}
		else{
			//error value will not fit into register. Overflow
			System.out.println("Error: Integer value:" + value + "does not fit into register of " + numOfBits + " bits");
			
		}
		
	}
	
	/**
	 * Returns the value of the register as an integer.
	 * @return The value of the register.
	 */
	public int getValue(){
		return reg;
	}
	
	/**
	 * Gets the opcode, or first eight bits, of the value of the register.
	 * @return The opcode as an integer.
	 */
	public int getOpCode(){
		String hex = Integer.toHexString(reg);
		// In case the hex string began with 0's, in which case they were cut off
		while (hex.length() < 8) {
			String temp = new String(hex);
			hex = new String("0" + temp);
		}
		return Integer.parseInt(hex.substring(0,2), 16);
	}
	
	/**
	 * Gets the XR field of the register.
	 * @return The value of the XR field.
	 */
	public int getXR(){
		String hex = Integer.toHexString(reg);
		// In case the hex string began with 0's, in which case they were cut off
		while (hex.length() < 8) {
			String temp = new String(hex);
			hex = new String("0" + temp);
		}
		return Integer.parseInt(hex.substring(2,3), 16)/2;
	}
	
	/**
	 * Gets the debug bit of the register.
	 * @return The value of the debug bit.
	 */
	public int getDebug(){
		String hex = Integer.toHexString(reg);
		// In case the hex string began with 0's, in which case they were cut off
		while (hex.length() < 8) {
			String temp = new String(hex);
			hex = new String("0" + temp);
		}
		return Integer.parseInt(hex.substring(2,3), 16) % 2;
	}
	
	/**
	 * Gets the IOWD flag of the register.
	 * @return The value of the IOWD flag.
	 */
	public int getIOWDFlag(){
		String hex = Integer.toHexString(reg);
		// In case the hex string began with 0's, in which case they were cut off
		while (hex.length() < 8) {
			String temp = new String(hex);
			hex = new String("0" + temp);
		}
		return Integer.parseInt(hex.substring(3,4), 16)/4;
	}
	
	/**
	 * Gets the address flag field bits of the register.
	 * @return The value of the address field.
	 */
	public int getAddrFlag(){
		String hex = Integer.toHexString(reg);
		// In case the hex string began with 0's, in which case they were cut off
		while (hex.length() < 8) {
			String temp = new String(hex);
			hex = new String("0" + temp);
		}
		return Integer.parseInt(hex.substring(3,4), 16)%4;
	}
	
	/**
	 * Gets the address field, or the last sixteen bits, of the value of the register.
	 * @return The address as an integer.
	 */
	public int getAddressField(){
		// TODO convert from 2's comp
		String hex = Integer.toHexString(reg);
		// In case the hex string began with 0's, in which case they were cut off
		while (hex.length() < 8) {
			String temp = new String(hex);
			hex = new String("0" + temp);
		}
		return Integer.parseInt(hex.substring(4), 16);
	}

}
